package com.yjt.common.hibernate.id;

import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.type.Type;

public class SequenceGenerator implements Configurable, IdentifierGenerator {
	
	private final static String SEQUENCE_TYPE = "sequenceType";
	
	private final static String ID_DECORATOR = "idDecorator";
	
	private final static String seqGenerateSp = "{call sproc_generate_seq(?)}";
	
	private String sequenceType;
	
	private Type idType;
	
	private IdDecorator idDecorator;
	
	public SequenceGenerator(){
		
	}

	@Override
	public void configure(Type type, Properties params, Dialect dialect)
			throws MappingException {
		sequenceType =  params.getProperty(SEQUENCE_TYPE);
		idType = type;
		String idDecoratorClassName = params.getProperty(ID_DECORATOR);
		if(idDecoratorClassName != null){
			try{
				idDecorator = (IdDecorator) Class.forName(idDecoratorClassName).newInstance();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		idDecorator = idDecorator == null ? new DefaultIdDecorator() : idDecorator;
	}

	@Override
	public Serializable generate(SessionImplementor session, Object obj)
			throws HibernateException {
		CallableStatement callableSt = null;
		Serializable id = null;
		try{
			callableSt = session.getBatcher().prepareCallableStatement(seqGenerateSp);
			callableSt.setString(1, sequenceType);
			
			ResultSet rs = callableSt.executeQuery();
			if(rs.next()){
				id = idDecorator.decorator(new Long(rs.getLong(1)), idType);
			}
			
			return id;
		}catch(Exception e){
			throw new HibernateException("Generate sequence fail" + e.getMessage());
		}finally{
			try{
				session.getBatcher().closeStatement(callableSt);
			}catch(Exception e){
				throw new HibernateException("Close callableStatement fail!" + e.getMessage());
			}
		}
	}
}
